using System;
using System.Collections.Generic;

using Flood.Extensions;

namespace Flood.Log
{
	public class ChangeList : IChangeList
	{
		private readonly Stack<IChange> changes = new Stack<IChange>();
		private readonly HashSet<Shape> touched = new HashSet<Shape>();
		private bool markTouched;
		private bool undoing;

		#region IChangeList Members

		public void Add(IChange change)
		{
			if (!undoing)
			{
				changes.Push(change);
			}
			if (markTouched)
			{
				Shape shape = change.Shape;
				if (touched.Add(shape))
				{
					shape.DisableCaching();
				}
			}
		}

		public void CheckPoint()
		{
			changes.Push(new CheckPointChange());
		}

		public void Undo()
		{
			markTouched = false;
			try
			{
				undoing = true;

				while (changes.Peek() != null)
				{
					IChange change = changes.Pop();
					if (change is CheckPointChange)
					{
						return;
					}
					change.Undo();
				}
			}
			finally
			{
				EnableCachingOnTouched();
				undoing = false;
			}
		}

		#endregion

		public void Clear()
		{
			EnableCachingOnTouched();
			changes.Clear();
		}

		public void DisableCachingOnTouched()
		{
			touched.Clear();
			markTouched = true;
		}

		public void EnableCachingOnTouched()
		{
			markTouched = false;
			touched.ForEach(shape => shape.EnableCaching());
			touched.Clear();
		}

		private class CheckPointChange : IChange
		{
			#region IChange Members

			public void Undo()
			{
			}

			public Shape Shape
			{
				get { throw new NotImplementedException(); }
			}

			#endregion
		}
	}
}